package ms.maplestory.boot.loaders;

import lombok.extern.slf4j.Slf4j;
import ms.maplestory.boot.ServerConstants;
import ms.maplestory.boot.loaders.container.ReactorInfo;
import ms.maplestory.boot.util.Rect;
import ms.maplestory.boot.util.Util;
import ms.maplestory.boot.util.XMLApi;
import org.w3c.dom.Node;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;

import static ms.maplestory.boot.loaders.MainLoader.INFO_OUT;

@Slf4j
public class ReactorData {

    private static HashMap<Integer, ReactorInfo> reactorInfo = new HashMap<>();

    public static void generateDatFiles() {
        log.info("Started generating reactor data.");
        long start = System.currentTimeMillis();
        loadReactorsFromWZ();
        saveReactorsToDat(String.format("%s/reactors", ServerConstants.DAT_DIR));
        log.info(String.format("Completed generating reactor data in %dms.", System.currentTimeMillis() - start));
    }

    private static void loadReactorsFromWZ() {
        String wzDir = ServerConstants.WZ_DIR + "/Reactor.wz";
        File dir = new File(wzDir);
        File[] files = dir.listFiles();
        for (File file : files) {
            int id = Integer.parseInt(file.getName().replace(".img.xml", ""));
            ReactorInfo ri = new ReactorInfo();
            ri.setId(id);
            Node node = XMLApi.getAllChildren(XMLApi.getRoot(file)).get(0);
            Node questNode = XMLApi.getFirstChildByNameBF(node, "quest");
            if (questNode != null) {
                ri.setQuest(Integer.parseInt(XMLApi.getNamedAttribute(questNode, "value")));
            }
            Node actionNode = XMLApi.getFirstChildByNameBF(node, "action");
            if (actionNode != null) {
                ri.setAction(XMLApi.getNamedAttribute(actionNode, "value"));
            }
            Node mainInfoNode = XMLApi.getFirstChildByNameBF(node, "info");
            for (Node infoNode : XMLApi.getAllChildren(mainInfoNode)) {
                String name = XMLApi.getNamedAttribute(infoNode, "name");
                String value = XMLApi.getNamedAttribute(infoNode, "value");
                switch (name) {
                    case "info":
                        ri.setInfo(value);
                        break;
                    case "lt":
                        int x1 = Integer.parseInt(XMLApi.getNamedAttribute(infoNode, "x"));
                        int y1 = Integer.parseInt(XMLApi.getNamedAttribute(infoNode, "y"));
                        Node rbNode = XMLApi.getFirstChildByNameBF(mainInfoNode, "rb");
                        int x2 = Integer.parseInt(XMLApi.getNamedAttribute(rbNode, "x"));
                        int y2 = Integer.parseInt(XMLApi.getNamedAttribute(rbNode, "y"));
                        ri.setRect(new Rect(x1, y1, x2, y2));
                        break;
                    case "name":
                        ri.setName(value);
                        break;
                    case "link":
                        ri.setLink(Integer.parseInt(value));
                        break;
                    case "activateByTouch":
                        ri.setActivateByTouch("1".equalsIgnoreCase(value));
                        break;
                    case "removeInFieldSet":
                        ri.setRemoveInFieldSet("1".equalsIgnoreCase(value));
                        break;
                    case "notHitable":
                        ri.setNotHittable("1".equalsIgnoreCase(value));
                        break;
                    case "backTile":
                    case "rb":
                        break;
                    default:
                        if (INFO_OUT)
                            log.warn(String.format("[Reactor] Unhandled info node id %d, %s, value %s", ri.getId(), name, value));
                }
            }
            reactorInfo.put(ri.getId(), ri);
        }
    }

    private static void saveReactorsToDat(String dir) {
        Util.makeDirIfAbsent(dir);
        for (ReactorInfo ri : reactorInfo.values()) {
            File file = new File(String.format("%s/%d.dat", dir, ri.getId()));
            try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(file))) {
                dos.writeInt(ri.getId());
                dos.writeInt(ri.getLink());
                dos.writeInt(ri.getQuest());
                dos.writeUTF(ri.getInfo());
                dos.writeUTF(ri.getName());
                dos.writeUTF(ri.getAction());
                dos.writeBoolean(ri.isRemoveInFieldSet());
                dos.writeBoolean(ri.isActivateByTouch());
                dos.writeBoolean(ri.isNotHittable());
                dos.writeBoolean(ri.getRect() != null);
                if (ri.getRect() != null) {
                    Rect r = ri.getRect();
                    dos.writeShort(r.getLeft());
                    dos.writeShort(r.getTop());
                    dos.writeShort(r.getRight());
                    dos.writeShort(r.getBottom());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
